#include "BSplineCurves3.h"

namespace cagd
{
    BSplineCurve3::BSplineCurve3(KnotVector::Type type, GLuint p, GLuint n, GLdouble u_min, GLdouble u_max, GLenum data_usage_flag):
            LinearCombination3(u_min, u_max, n + 1, data_usage_flag),
            _n(n),
            _kv(0)
    {
        _kv = new KnotVector(type, p, n, u_min, u_max);
    }

    // homework: finish the implementation of the class BSplineCurve3

    // homework: using the specified knot vector, redeclare and define the inherited pure virtual methods
    //           (calculate at least the zeroth order derivatives)
    GLboolean BSplineCurve3::BlendingFunctionValues(GLdouble u, RowMatrix<GLdouble>& values) const {

        TriangularMatrix<GLdouble> N;
        GLuint i;

        if (!_kv->EvaluateNonZeroBSplineFunctions(u, i, N))
        {
            values.ResizeColumns(0);
            return GL_FALSE;
        }

        GLuint p = _kv->GetOrder();

        values.ResizeColumns(p);

        for (GLuint j = 0; j <= i - p; ++j)
        {
            values[j] = 0.0;
        }

        GLuint offset = i - p + 1;
        for (GLuint j = offset; j <= i; ++j)
        {
            values[j] = N(p-1, j - offset);
        }

        for (GLuint j = i + 1; j <= (_kv->GetType() != KnotVector::PERIODIC ? _n + p : _n + 2 * p - 1); ++j)
        {
            values[j] = 0.0;
        }

        return GL_TRUE;
    }

    GLboolean BSplineCurve3::CalculateDerivatives(GLuint max_order_of_derivatives, GLdouble u, Derivatives& d) const {
        RowMatrix<GLdouble> values;
        if (BlendingFunctionValues(u,values)) {
            TriangularMatrix<GLdouble> N;
            GLuint i;
            GLuint p = _kv->GetOrder();

            if (!_kv->EvaluateNonZeroBSplineFunctions(u, i, N))
            {
                return GL_FALSE;
            }

            GLuint offset = i - p + 1 - max_order_of_derivatives;
            for (GLuint j = offset; j <= i; ++j)
            {
                d[j] = N(p-1 - max_order_of_derivatives, j - offset) * _data[j-offset];
            }
            /*d.ResizeRows(values.GetColumnCount());
            for (GLuint i = 0; i < values.GetColumnCount(); i++) {
                d[i] = values[i];
            }*/
            return GL_TRUE;
        }

        return GL_FALSE;
    }

    // homework: free the dynamically allocated knot vector
    BSplineCurve3::~BSplineCurve3() {
        if (_kv) {
            delete _kv, _kv = 0;
        }
    }
}
